﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using System.Xml.Linq;
using fbasync.web.Controls;
using fbasync.web.Controls.TemplateEditor;
using System.Globalization;

namespace fbasync.web.Data
{
    public class TemplateEditorDataAccess
    {
        public delegate void AsyncCompleted(AsyncState sender);

        public class AsyncState
        {
            private AsyncCompleted _asyncCompleted;
            private string _errorMessage = String.Empty;

            public string ErrorMessage
            {
                get { return  _errorMessage; }
            }

            public event AsyncCompleted Completed
            {
                add { _asyncCompleted = value; }
                remove { _asyncCompleted = null; }
            }

            public void HandleException(Exception ex)
            {
                if (!String.IsNullOrEmpty(_errorMessage)) _errorMessage += "\n";

                _errorMessage += ex.Message;
            }

            internal void OnCompleted()
            {
                if (null != _asyncCompleted) _asyncCompleted(this);
            }
        }

        private const string DataFileNamePattern = "~/App_Data/{0}_data.xml";

        private const string RootExportConfig = "<?xml version='1.0' encoding='utf-8' ?><facebookasync></facebookasync>";
        private const string BundleIdAttribute = "bundleid";
        private const string NameAttribute = "name";
        private const string ApplicationName = "application";
        private const string EventsName = "events";

        public static TemplateEditorDataSet DataSet
        {
            get
            {
                ApplicationInfo currentApplication = ApplicationManager.CurrentApplication;

                return null == currentApplication ? null : GetDataSet(currentApplication.Name);
            }
        }

        private static TemplateEditorDataSet LoadDataSet(string applicationName)
        {
            TemplateEditorDataSet result = new TemplateEditorDataSet();

            InitDataSet(result, applicationName);

            return result;
        }

        private static TemplateEditorDataSet GetDataSet(string applicationName)
        {
            if (String.IsNullOrEmpty(applicationName)) return null;

            TemplateEditorDataSet result = (TemplateEditorDataSet)HttpContext.Current.Session["TemplateEditorDataSet"];

            if (null != result)
            {
                TemplateEditorDataSet.ApplicationRow appRow = (TemplateEditorDataSet.ApplicationRow)result.Application.Rows[0];

                if (!applicationName.Equals(appRow.Name))
                {
                  // Not sure it is a good idea to save the previous data without user's confirmation
                  //  StoreDataSetIfNecessary(result);

                    result = null;
                }
            }

            if (null == result)
            {
                result = LoadDataSet(applicationName);

                HttpContext.Current.Session["TemplateEditorDataSet"] = result;
            }
            
            return result;
        }

        private static string DataFileName(string applicationName)
        {
            return HttpContext.Current.Request.MapPath(String.Format(DataFileNamePattern, applicationName));
        }

        private static void InitDataSet(TemplateEditorDataSet dataSet, string applicationName)
        {
            string dataFileName = DataFileName(applicationName);

            if (File.Exists(dataFileName))
            {
                dataSet.ReadXml(dataFileName);
                dataSet.AcceptChanges();
            }
            else
            {
                ApplicationInfo appInfo = ApplicationManager.GetApplicationByName(applicationName);

                if (null != appInfo)
                {
                    dataSet.Application.AddApplicationRow(appInfo.Name, appInfo.FacebookApiKey, appInfo.FacebookSecret);
                }
            }
        }

        public static void AssignApplicationTemplates(IList<StoryTemplateBundle> templates)
        {
            AssignApplicationTemplates(templates, false);
        }

        public static void AssignApplicationTemplates(IList<StoryTemplateBundle> templates, bool forceStoring)
        {
            IList<DataRow> foundRows = new List<DataRow>();

            foreach (StoryTemplateBundle bundle in templates)
            {
                foundRows.Add(AssignStoryTemplateBundle(bundle));
            }

            RemoveNotFoundStoryTemplates(foundRows);

            if (forceStoring) StoreDataSet(DataSet);
            else
            {
                StoreDataSetIfNecessary(DataSet);
            }
        }

        private static void RemoveNotFoundStoryTemplates(IList<DataRow> foundRows)
        {
            TemplateEditorDataSet dataSet = DataSet;
            DataRow bundleRow;

            for (int rowIndex = dataSet.StoryTemplateBundle.Count - 1; rowIndex >= 0; rowIndex--)
            {
                bundleRow = dataSet.StoryTemplateBundle.Rows[rowIndex];

                if (foundRows.IndexOf(bundleRow) == -1)
                {
                    bundleRow.Delete();
                }
            }
        }

        private static DataRow AssignStoryTemplateBundle(StoryTemplateBundle bundle)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow bundleRow;
     
            DataView dataView = new DataView(dataSet.StoryTemplateBundle);

            dataView.RowFilter = String.Format("BundleId={0}", bundle.ID.Value);

            bundleRow = dataView.Count == 0 ? null : (TemplateEditorDataSet.StoryTemplateBundleRow)dataView[0].Row;

            if (null == bundleRow) // Maybe we just created a new bundle
            {
                int storyHashCode = Utils.GetStoryHashCode(bundle);

                foreach (TemplateEditorDataSet.StoryTemplateBundleRow row in dataSet.StoryTemplateBundle.Rows)
                {
                    if (row.IsStoryHashCodeNull()) continue;

                    if (storyHashCode.Equals(row.StoryHashCode))
                    {
                        bundleRow = row;

                        bundleRow.BundleId = bundle.ID.Value;
                        bundleRow.Created = bundle.Created.Value;
                        bundleRow.SetStoryHashCodeNull();

                        break;
                    }
                }
            }

            if (null == bundleRow)
            {
                bundleRow = dataSet.StoryTemplateBundle.NewStoryTemplateBundleRow();

                bundleRow.BundleId = bundle.ID.Value;
                bundleRow.ApplicationRow = CurrentApplicationRow ;

                bundleRow.Name = String.Format(Consts.NewBundleName, bundleRow.UniqueId);
                dataSet.StoryTemplateBundle.AddStoryTemplateBundleRow(bundleRow);
            }

            bundleRow.Created = bundle.Created.GetValueOrDefault(DateTime.Now);

            if (null != bundle.FullStory)
            {
                if (String.IsNullOrEmpty(bundle.FullStory.template_title)) bundleRow.SetFullStoryTitleNull();
                else
                {
                    bundleRow.FullStoryTitle = bundle.FullStory.template_title;
                }

                if (String.IsNullOrEmpty(bundle.FullStory.template_body)) bundleRow.SetFullStoryBodyNull();
                {
                    bundleRow.FullStoryBody = bundle.FullStory.template_body;
                }
            }
            else
            {
                bundleRow.SetFullStoryBodyNull();
                bundleRow.SetFullStoryTitleNull();
            }

            foreach (StoryTemplate onelineStory in bundle.OneLineStories)
            {
                AssignOneLineStoryTemplate(bundleRow.UniqueId, onelineStory);
            }

            foreach (StoryTemplate shortStory in bundle.ShortStories)
            {
                AssignShortStoryTemplate(bundleRow.UniqueId, shortStory);
            }

            return bundleRow;
        }

        internal static StoryTemplateBundle GetStoryTemplateBundle(int uniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow bundleRow = dataSet.StoryTemplateBundle.FindByUniqueId(uniqueId);

            if (bundleRow == null) return null;

            return GetStoryTemplateBundle(bundleRow);
        }

        private static StoryTemplateBundle GetStoryTemplateBundle(TemplateEditorDataSet.StoryTemplateBundleRow bundleRow)
        {
            StoryTemplateBundle result = new StoryTemplateBundle();

            if (!(bundleRow.IsFullStoryTitleNull() || String.IsNullOrEmpty(bundleRow.FullStoryTitle)))
            {
                result.FullStory = new StoryTemplate();
                result.FullStory.template_title = bundleRow.FullStoryTitle;
                result.FullStory.template_body = bundleRow.IsFullStoryBodyNull() ? String.Empty : bundleRow.FullStoryBody;
            }

            result.OneLineStories = GetBundleOneLineTemplates(bundleRow.UniqueId);
            result.ShortStories = GetBundleShortTemplates(bundleRow.UniqueId);

            bundleRow.StoryHashCode = Utils.GetStoryHashCode(result);

            return result;
        }

        private static IList<StoryTemplate> GetBundleShortTemplates(int bundleUniqueId)
        {
            DataView dataView = new DataView(DataSet.ShortStoryTemplate);

            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            if (dataView.Count == 0) return null;

            IList<StoryTemplate> result = new List<StoryTemplate>();

            foreach (DataRowView dataRow in dataView)
            {
                result.Add(GetShortStoryTemplate((TemplateEditorDataSet.ShortStoryTemplateRow)dataRow.Row));
            }

            return result;
        }

        private static StoryTemplate GetShortStoryTemplate(TemplateEditorDataSet.ShortStoryTemplateRow templateRow)
        {
            StoryTemplate result = new StoryTemplate();

            result.template_title = templateRow.Title;
            result.template_body = templateRow.IsBodyNull() ? String.Empty : templateRow.Body;

            return result;
        }

        private static IList<StoryTemplate> GetBundleOneLineTemplates(int bundleUniqueId)
        {
            DataView dataView = new DataView(DataSet.OneLineTemplate);

            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            if (dataView.Count == 0) return null;

            IList<StoryTemplate> result = new List<StoryTemplate>();

            foreach (DataRowView dataRow in dataView)
            {
                result.Add(GetOneLineTemplate((TemplateEditorDataSet.OneLineTemplateRow) dataRow.Row));
            }

            return result;
        }

        private static StoryTemplate GetOneLineTemplate(TemplateEditorDataSet.OneLineTemplateRow templateRow)
        {
            StoryTemplate result = new StoryTemplate();

            result.template_title = templateRow.Title;

            return result;
        }

        private static void AssignShortStoryTemplate(int bundleUniqueId, StoryTemplate shortStory)
        {
            TemplateEditorDataSet dataSet = DataSet;

            DataView dataView = new DataView(dataSet.ShortStoryTemplate);
            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            TemplateEditorDataSet.ShortStoryTemplateRow shortStoryRow;

            foreach (DataRowView rowView in dataView)
            {
                shortStoryRow = (TemplateEditorDataSet.ShortStoryTemplateRow)rowView.Row;

                if (shortStory.template_title.Equals(shortStoryRow.Title) &&
                    shortStory.template_body.Equals(shortStoryRow.IsBodyNull() ? String.Empty : shortStoryRow.Body))
                {
                    return;
                }
            }

            shortStoryRow = dataSet.ShortStoryTemplate.NewShortStoryTemplateRow();

            shortStoryRow.BundleUniqueId = bundleUniqueId;
            shortStoryRow.Title = shortStory.template_title;
            shortStoryRow.Body = shortStory.template_body;

            dataSet.ShortStoryTemplate.AddShortStoryTemplateRow(shortStoryRow);
        }

        private static void AssignOneLineStoryTemplate(int bundleUniqueId, StoryTemplate onelineStory)
        {
            TemplateEditorDataSet dataSet = DataSet;

            DataView dataView = new DataView(dataSet.OneLineTemplate);
            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            TemplateEditorDataSet.OneLineTemplateRow oneLineRow;

            foreach (DataRowView rowView in dataView)
            {
                oneLineRow = (TemplateEditorDataSet.OneLineTemplateRow)rowView.Row;

                if (onelineStory.template_title.Equals(oneLineRow.Title)) return;
            }

            oneLineRow = dataSet.OneLineTemplate.NewOneLineTemplateRow();

            oneLineRow.BundleUniqueId = bundleUniqueId;
            oneLineRow.Title = onelineStory.template_title;

            dataSet.OneLineTemplate.AddOneLineTemplateRow(oneLineRow);
        }

        public static void StoreDataSetIfNecessary(TemplateEditorDataSet dataSet)
        {
            if (dataSet.HasChanges()) StoreDataSet(dataSet);
        }

        public static void StoreDataSet(TemplateEditorDataSet dataSet)
        {
            string applicationName = dataSet.Application.Rows[0]["Name"].ToString();

            string dataFileName = DataFileName(applicationName);

            dataSet.AcceptChanges();

            dataSet.WriteXml(dataFileName);
        }

        internal static bool IsBundleChanged(int bundleUniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow bundleRow = dataSet.StoryTemplateBundle.FindByUniqueId(bundleUniqueId);

            if (null == bundleRow) return false;

            if (bundleRow.RowState != DataRowState.Unchanged) return true;

            DataView dataView = new DataView(dataSet.OneLineTemplate);

            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            for (int rowIndex = 0; rowIndex < dataView.Count; rowIndex++)
            {
                if (dataView[rowIndex].Row.RowState != DataRowState.Unchanged) return true;
            }

            dataView = new DataView(dataSet.ShortStoryTemplate);

            dataView.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            for (int rowIndex = 0; rowIndex < dataView.Count; rowIndex++)
            {
                if (dataView[rowIndex].Row.RowState != DataRowState.Unchanged) return true;
            }

            return false;
        }

        internal static int GetUniqueBundleId(long bundleId)
        {
            DataView dataView = new DataView(DataSet.StoryTemplateBundle);

            dataView.RowFilter = String.Format("BundleId={0}", bundleId);

            return ((TemplateEditorDataSet.StoryTemplateBundleRow)dataView[0].Row).UniqueId;
        }

        internal static TemplateEditorDataSet.StoryTemplateBundleRow CreateNewStoryTemplateBundle()
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow result = dataSet.StoryTemplateBundle.NewStoryTemplateBundleRow();

            result.ApplicationRow = CurrentApplicationRow;
            result.BundleId = Consts.UnknownBundleId;
            result.Created = DateTime.Now;
            
            dataSet.StoryTemplateBundle.AddStoryTemplateBundleRow(result);

            result.Name = String.Format(Consts.NewBundleName, result.UniqueId);

            CreateNewOneLineStory(result.UniqueId);
                
            return result;
        }

        internal static string DefaultOneLineTitle
        {
            get
            {
                return String.Format(Consts.NewOnelineTemplateTitle, CurrentApplicationRow.Name);
            }
        }

        internal static TemplateEditorDataSet.ApplicationRow CurrentApplicationRow
        {
            get
            {
                return (TemplateEditorDataSet.ApplicationRow)DataSet.Application.Rows[0];
            }
        }

        internal static DataView GetBundleOneLineStores(int bundleUniqueId)
        {
            DataView result = new DataView(DataSet.OneLineTemplate);

            result.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            return result;
        }

        internal static DataView GetBundleShortStores(int bundleUniqueId)
        {
            DataView result = new DataView(DataSet.ShortStoryTemplate);

            result.RowFilter = String.Format("BundleUniqueId={0}", bundleUniqueId);

            return result;
        }

        internal static void DeleteStoryTemplateBundle(int bundleUniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow rowToDelete = dataSet.StoryTemplateBundle.FindByUniqueId(bundleUniqueId);

            if (rowToDelete != null)
            {
                rowToDelete.Delete();

                StoreDataSetIfNecessary(dataSet);
            }
        }

        internal static bool IsEditingMode()
        {
            TemplateEditorDataSet dataSet = DataSet;

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow bundleRow in dataSet.StoryTemplateBundle.Rows)
            {
                if (IsBundleChanged(bundleRow.UniqueId)) return true;
            }

            return false;
        }

        internal static void CancelBundleEditing(int bundleUniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow rowToCancel = dataSet.StoryTemplateBundle.FindByUniqueId(bundleUniqueId);

            if (rowToCancel != null)
            {
                rowToCancel.RejectChanges();
            }
        }

        internal static string AcceptBundleChanges(long bundleId, int bundleUniqueId)
        {
            return AcceptBundleChanges(bundleId, DataSet.StoryTemplateBundle.FindByUniqueId(bundleUniqueId));
        }

        internal static string AcceptBundleChanges(long bundleId, TemplateEditorDataSet.StoryTemplateBundleRow bundleRow)
        {
            if (null == bundleRow) return String.Empty;

            bundleRow.BundleId = bundleId;
            if (bundleRow.IsCreatedNull()) bundleRow.Created = DateTime.Now;
            bundleRow.SetStoryHashCodeNull();
            bundleRow.AcceptChanges();

            return bundleRow.Name;
        }


        internal static void CreateNewOneLineStory(int bundleUniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.OneLineTemplateRow oneLineRow = dataSet.OneLineTemplate.NewOneLineTemplateRow();

            oneLineRow.BundleUniqueId = bundleUniqueId;
            oneLineRow.Title = DefaultOneLineTitle;

            dataSet.OneLineTemplate.AddOneLineTemplateRow(oneLineRow);
        }

        internal static void CreateNewShortStory(int bundleUniqueId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            TemplateEditorDataSet.ShortStoryTemplateRow shortStoryRow = dataSet.ShortStoryTemplate.NewShortStoryTemplateRow();

            shortStoryRow.BundleUniqueId = bundleUniqueId;
            shortStoryRow.Title = DefaultOneLineTitle;

            dataSet.ShortStoryTemplate.AddShortStoryTemplateRow(shortStoryRow);
        }

        internal static void DeleteOneLineStory(int bundleUniqueId, int uniqueId)
        {
            TemplateEditorDataSet.OneLineTemplateRow oneLineRow = DataSet.OneLineTemplate.FindByBundleUniqueIdUniqueId(bundleUniqueId, uniqueId);

            if (null != oneLineRow)
            {
                oneLineRow.Delete();
            }
        }

        internal static void DeleteShortStory(int bundleUniqueId, int uniqueId)
        {
            TemplateEditorDataSet.ShortStoryTemplateRow shortStoryRow = DataSet.ShortStoryTemplate.FindByBundleUniqueIdUniqueId(bundleUniqueId, uniqueId);

            if (null != shortStoryRow)
            {
                shortStoryRow.Delete();
            }
        }

        internal static XmlDocument PrepareExportConfig()
        {
            XmlDocument result = new XmlDocument();

            result.LoadXml(RootExportConfig);

            return result;
        }

        internal static XmlDocument PrepareApplicationConfig(XmlDocument document, string appName, out XmlNode eventsNode)
        {
            XmlDocument result = null == document ? PrepareExportConfig() : document;

            XmlElement applicationNode = result.CreateElement(ApplicationName);

            XmlAttribute attribute = result.CreateAttribute(NameAttribute);
            attribute.Value = appName;

            applicationNode.Attributes.Append(attribute);

            result.DocumentElement.AppendChild(applicationNode);

            eventsNode = result.CreateElement(EventsName);

            applicationNode.AppendChild(eventsNode);

            return result;
        }

        internal static XmlDocument ExportFBConfig(string appName)
        {
            XmlDocument result = PrepareExportConfig();

            if (Consts.DefaultConfigFileName.Equals(appName)) // We need all the applicatinos
            {
                foreach (ApplicationInfo appInfo in ApplicationManager.Applications)
                {
                    if (appInfo.IsCustom) continue;

                    ExportApplicationConfig(result, appInfo.Name);
                }
            }
            else
            {
                ExportApplicationConfig(result, appName);
            }

            return result;
        }

        internal static void ExportApplicationConfig(XmlDocument document, string appName)
        {
            XmlNode eventsNode;

            PrepareApplicationConfig(document, appName, out eventsNode);

            if (null == eventsNode) return;

            XmlElement bundleNode;
            XmlAttribute attribute;

            TemplateEditorDataSet dataSet = LoadDataSet(appName);

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow bundleRow in dataSet.StoryTemplateBundle.Rows)
            {
                bundleNode = document.CreateElement(bundleRow.Name);

                attribute = document.CreateAttribute(BundleIdAttribute);
                attribute.Value = bundleRow.BundleId.ToString();

                bundleNode.Attributes.Append(attribute);

                eventsNode.AppendChild(bundleNode);
            }
        }

        internal static void ImportFromApplication(string apiKey, AsyncState asyncState)
        {
            string appName = ApplicationManager.GetApplicationByApiKey(apiKey).Name;

            TemplateEditorDataSet importDataSet = LoadDataSet(appName);
            TemplateEditorDataSet currentDataSet = DataSet;

            TemplateEditorDataSet.StoryTemplateBundleRow newBundleRow;
            TemplateEditorDataSet.OneLineTemplateRow newOneLineRow, importOneLineRow;
            TemplateEditorDataSet.ShortStoryTemplateRow newShortStoryRow, importShortStoryRow;

            DataView currentBundleDataView = new DataView(currentDataSet.StoryTemplateBundle);
            DataView importStoriesView;

            long tempBundleId = -1;

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow importBundleRow in importDataSet.StoryTemplateBundle.Rows)
            {
                currentBundleDataView.RowFilter = String.Format("Name='{0}'", importBundleRow.Name);

                if (currentBundleDataView.Count > 0) continue; // We do not replace existing bundles

                newBundleRow = currentDataSet.StoryTemplateBundle.NewStoryTemplateBundleRow();

                newBundleRow.BundleId = tempBundleId--;
                newBundleRow.FacebookApiKey = apiKey;
                newBundleRow.Name = importBundleRow.Name;

                if (!importBundleRow.IsFullStoryTitleNull()) newBundleRow.FullStoryTitle = importBundleRow.FullStoryTitle;
                if (!importBundleRow.IsFullStoryBodyNull()) newBundleRow.FullStoryBody = importBundleRow.FullStoryBody;

                currentDataSet.StoryTemplateBundle.Rows.Add(newBundleRow);

                importStoriesView = new DataView(importDataSet.OneLineTemplate);
                importStoriesView.RowFilter = String.Format("BundleUniqueId={0}", importBundleRow.UniqueId);

                foreach (DataRowView importOneLineRowView in importStoriesView)
                {
                    importOneLineRow = (TemplateEditorDataSet.OneLineTemplateRow) importOneLineRowView.Row;

                    newOneLineRow = currentDataSet.OneLineTemplate.NewOneLineTemplateRow();

                    newOneLineRow.BundleUniqueId = newBundleRow.UniqueId;
                    newOneLineRow.Title = importOneLineRow.Title;

                    currentDataSet.OneLineTemplate.Rows.Add(newOneLineRow);
                }

                importStoriesView = new DataView(importDataSet.ShortStoryTemplate);
                importStoriesView.RowFilter = String.Format("BundleUniqueId={0}", importBundleRow.UniqueId);

                foreach (DataRowView importShortStoryRowView in importStoriesView)
                {
                    importShortStoryRow = (TemplateEditorDataSet.ShortStoryTemplateRow)importShortStoryRowView.Row;

                    newShortStoryRow = currentDataSet.ShortStoryTemplate.NewShortStoryTemplateRow();

                    newShortStoryRow.BundleUniqueId = newBundleRow.UniqueId;
                    newShortStoryRow.Title = importShortStoryRow.Title;

                    if (!importShortStoryRow.IsBodyNull()) newShortStoryRow.Body = importShortStoryRow.Body;

                    currentDataSet.ShortStoryTemplate.Rows.Add(newShortStoryRow);
                }
            }

            AcceptEditedTemplates(currentDataSet, asyncState);
        }

        private static void AcceptEditedTemplates(TemplateEditorDataSet dataSet, AsyncState asyncState)
        {
            TemplateEditorDataSet.StoryTemplateBundleRow bundleRow;
            StoryTemplateBundle newBundle;

            short processedRows = 0;
            long newBundleId;

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow checkingRow in dataSet.StoryTemplateBundle)
            {
                if (checkingRow.RowState == DataRowState.Added) processedRows++;
            }

            if (0 == processedRows) return;

            Global.Connection.SetUserPreferenceCompleted +=
            (preferenceSender, preferenceResult) =>
            {
                if (null != preferenceResult.Error)
                {
                    if (null != asyncState) asyncState.HandleException(preferenceResult.Error);
                    else
                    {
                        ExceptionHandler.HandleException(preferenceResult.Error);
                    }
                }
            };

            Global.Connection.RegisterTemplateBundleCompleted +=
            (registerSender, registerResult) =>
            {
                processedRows--;

                if (null == registerResult.Error)
                {
                    newBundleId = registerResult.Result;

                    string bundleName = AcceptBundleChanges(newBundleId, (int)registerResult.UserState);

                    if (!String.IsNullOrEmpty(bundleName)) // We store the bundle names in the user preferences
                    {
                        // I have permanent exception here: 
                        //Global.Connection.SetUserPreferenceAsync(processedRows, String.Format("{0}:{1}", newBundleId, bundleName));
                    }
                }
                else
                {
                    if (null != asyncState) asyncState.HandleException(registerResult.Error);
                    else
                    {
                        ExceptionHandler.HandleException(registerResult.Error);
                    }
                }

                if (0 == processedRows)
                {
                    RefreshTemplates(asyncState);
                }
            };

            for (int rowIndex = dataSet.StoryTemplateBundle.Rows.Count - 1; rowIndex >= 0; rowIndex--)
            {
                bundleRow = (TemplateEditorDataSet.StoryTemplateBundleRow)dataSet.StoryTemplateBundle.Rows[rowIndex];

                if (bundleRow.RowState != DataRowState.Added) continue;
               
                newBundle = TemplateEditorDataAccess.GetStoryTemplateBundle(bundleRow);

                Global.Connection.RegisterTemplateBundleAsync(newBundle, bundleRow.UniqueId);
            }
        }

        internal static void RefreshTemplates(AsyncState asyncState)
        {
            Global.Connection.GetRegisteredTemplateBundlesCompleted +=
                    (sender, e) =>
                    {
                        if (null != e.Error)
                        {
                            if (null != asyncState) asyncState.HandleException(e.Error);
                            else
                            {
                                ExceptionHandler.HandleException(e.Error);
                            }
                        }
                        else
                        {
                            AssignApplicationTemplates(e.Result, true);
                        }

                        if (null != asyncState)
                        {
                            asyncState.OnCompleted();
                        }
                    };

            Global.Connection.GetRegisteredTemplateBundlesAsync(null);
        }

        internal static void SetEditMode(long bundleId)
        {
            TemplateEditorDataSet dataSet = DataSet;

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow templateRow in dataSet.StoryTemplateBundle.Rows)
            {
                if (templateRow.BundleId.Equals(bundleId))
                {
                    templateRow.StoryHashCode = DateTime.Now.Ticks.ToString().GetHashCode();

                    break;
                }
            }
        }

        internal static int GetBundleByName(string name)
        {
            if (String.IsNullOrEmpty(name)) return Consts.UnknownUniqueBundleId;

            TemplateEditorDataSet dataSet = DataSet;

            foreach (TemplateEditorDataSet.StoryTemplateBundleRow templateRow in dataSet.StoryTemplateBundle.Rows)
            {
                if (name.Equals(templateRow.Name, StringComparison.InvariantCultureIgnoreCase)) return templateRow.UniqueId;
            }

            return Consts.UnknownUniqueBundleId;
        }
    }
}
